package main

import (
	"bufio"
	"fmt"
	"os"
	"slices"
	"strings"
	"sync"
	"time"
)

type Buffer struct {
	List    []BufferBlock
	Timeout time.Time
}

type BufferBlock struct {
	Code string
	Data map[string]string
}

var configBuffer sync.Map

func getConfig(config string) ([]BufferBlock, error) {
	if v, ok := configBuffer.Load(config); ok {
		if buffer, ok := v.(Buffer); ok && buffer.Timeout.After(time.Now()) {
			return buffer.List, nil
		}
		configBuffer.Delete(config)
	}

	var list []BufferBlock
	file, err := os.Open(config)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	var codes []string
	var lines []string
	for scanner.Scan() {
		line := scanner.Text()
		fields := strings.Fields(line)
		if slices.Contains(fields, "config") && (slices.Contains(fields, "nodes") || slices.Contains(fields, "acl_rule") || slices.Contains(fields, "host") || slices.Contains(fields, "arpbind")) {
			lines = []string{line}
			continue
		}
		if len(lines) > 0 {
			if slices.Contains(fields, "option") {
				lines = append(lines, line)
			} else {
				codes = append(codes, "\n"+strings.Join(lines, "\n")+"\n")
				lines = []string{}
			}
		}
	}
	if len(lines) > 0 {
		codes = append(codes, "\n"+strings.Join(lines, "\n")+"\n")
		lines = []string{}
	}

	for _, code := range codes {
		block := BufferBlock{
			Code: code,
			Data: make(map[string]string),
		}
		for _, line := range strings.Split(code, "\n") {
			fields := strings.Fields(line)
			if len(fields) < 2 {
				continue
			}
			if len(fields) == 2 {
				fields = append(fields, "")
			}
			key := strings.Trim(strings.Trim(fields[1], "'"), "\"")
			var vals []string
			for i := 2; i < len(fields); i++ {
				vals = append(vals, strings.Trim(strings.Trim(fields[i], "'"), "\""))
			}
			block.Data[key] = strings.Join(vals, " ")
		}
		list = append(list, block)
	}
	configBuffer.Store(config, Buffer{
		List:    list,
		Timeout: time.Now().Add(5 * time.Second),
	})
	return list, nil
}

var deviceBuffer []Device
var deviceTimeout time.Time

// 从DHCP租约文件中获取设备信息
func getDevices() ([]Device, error) {
	if deviceTimeout.After(time.Now()) {
		return deviceBuffer, nil
	}
	deviceBuffer = make([]Device, 0)
	data, err := os.ReadFile(dhcpLeases)
	if err != nil {
		return nil, fmt.Errorf("读取DHCP租约文件失败: %v", err)
	}
	dhcps := strings.Split(string(data), "\n")

	data, _ = os.ReadFile(netArp)
	arps := string(data)

	statics, _ := getConfig(dhcpConfig)

	for _, line := range dhcps {
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}

		parts := strings.Fields(line)
		if len(parts) < 4 {
			continue // 跳过格式不正确的行
		}

		device := Device{
			MAC:    parts[1],
			IP:     parts[2],
			Name:   parts[3],
			Type:   "dynamic",
			Status: "offline",
		}

		// TODO: 从静态绑定中检查是否为静态IP
		for _, row := range statics {
			if mac, ok := row.Data["mac"]; ok && mac == device.MAC {
				device.Name = row.Data["name"]
				device.Type = "static"
			}
		}

		// TODO: 判断设备是否在线
		if strings.Contains(arps, device.MAC) || strings.Contains(arps, device.IP) {
			device.Status = "online"
		}

		deviceBuffer = append(deviceBuffer, device)
	}
	deviceTimeout = time.Now().Add(time.Second * 3)
	return deviceBuffer, nil
}
